Skip to content

Conversation

@deepshekhardas
Copy link

@deepshekhardas deepshekhardas commented Feb 2, 2026

Summary

Fixes #2914

Problem

\ rigger deploy\ hardcoded
pm install ...\ in the generated Dockerfile, ignoring the project's package manager (Yarn, pnpm). This caused failures for Yarn Workspaces (due to
ohoist\ being ignored) and prevented reproducible builds using lockfiles.

Fix

  • Modified \�uildImage.ts\ to support detected package managers.
  • Updates \�uildWorker.ts\ to detect PM and copy the lockfile (\yarn.lock, \pnpm-lock.yaml) to the build context.
  • Generates correct \RUN\ commands:
    • Yarn: \RUN yarn install`n - pnpm: \RUN corepack enable && RUN pnpm install`n - npm: \RUN npm i ...\ (default)
  • Added unit tests in \�uildImage.test.ts\ verifying Dockerfile generation logic.

Open with Devin

@changeset-bot
Copy link

changeset-bot bot commented Feb 2, 2026

🦋 Changeset detected

Latest commit: 4621b9c

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 2, 2026

Walkthrough

This pull request implements package manager and lockfile detection for container builds. The system now detects the active package manager (npm, yarn, or pnpm) and its corresponding lockfile, copies the lockfile into the build output, and generates appropriate install commands in the generated Containerfile. Four files are modified: a changeset entry documenting the fix, the build worker script to handle package manager detection and lockfile copying, the container image generation logic to support multiple package managers, and a new test file validating the behavior across different package manager scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The pull request description includes the issue reference, problem statement, and fix details, but the checklist and testing section are incomplete or missing. Complete the testing section with specific test steps and ensure the checklist items are properly addressed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately summarizes the main change: detecting package managers and lockfiles for correct deploy builds.
Linked Issues check ✅ Passed The code changes detect package managers, copy lockfiles, and generate appropriate install commands (yarn, pnpm, npm) as required by issue #2914.
Out of Scope Changes check ✅ Passed All changes are directly scoped to addressing issue #2914: package manager detection, lockfile handling, and Dockerfile generation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View issue and 3 additional flags in Devin Review.

Open in Devin Review

Comment on lines +1177 to +1180
return `
RUN corepack enable
RUN pnpm install
`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 pnpm install command generates inconsistent Dockerfile formatting with extra whitespace

The getInstallCommand function for pnpm returns a template literal with leading newlines and 6 spaces of indentation before each RUN command.

Click to expand

Issue

The pnpm case at buildImage.ts:1176-1180 returns:

return `
      RUN corepack enable
      RUN pnpm install
      `;

This produces output with leading/trailing newlines and inconsistent indentation:

COPY --chown=node:node package.json ./
# No lockfile path provided

      RUN corepack enable
      RUN pnpm install
      

# Now copy all the files

Comparison

The npm and yarn cases return clean single-line strings without extra whitespace:

  • "RUN yarn install" (line 1174)
  • "RUN npm i --no-audit --no-fund --no-save --no-package-lock" (line 1184)

Impact

While Docker technically accepts indented RUN commands, this produces messy Dockerfile output that is inconsistent with the rest of the generated file. The extra blank lines and indentation make the Dockerfile harder to read and debug.

Recommendation: Use consistent formatting without extra whitespace:

case "pnpm": {
  return "RUN corepack enable\nRUN pnpm install";
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@vibe-kanban-cloud
Copy link

Review Complete

Your review story is ready!

View Story

Comment !reviewfast on this PR to re-generate the story.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/cli-v3/src/deploy/buildImage.ts`:
- Around line 1171-1187: getInstallCommand currently prevents reproducible
installs and creates extra Docker layers; update it so npm uses "npm ci" (not
"npm i"), yarn uses a frozen/CI mode (e.g., "yarn install --frozen-lockfile"),
and pnpm runs corepack enable and install in a single RUN with pnpm's
frozen-lockfile flag (e.g., "corepack enable && pnpm install --frozen-lockfile")
to avoid multiple layers; modify the switch in getInstallCommand (check
packageManager?.name) to return these CI/immutable install commands and remove
the "--no-package-lock/--no-audit" pattern that disables lockfile enforcement.
🧹 Nitpick comments (2)
packages/cli-v3/src/build/buildWorker.ts (1)

212-233: Consider warning users when lockfile copy fails.

The current implementation silently fails (debug-level log only) when the lockfile cannot be copied. This could lead to non-reproducible builds without the user's awareness, especially if they expect the lockfile to be used.

💡 Proposed enhancement to warn users on lockfile copy failure
   if (lockFile) {
     try {
       await copyFile(
         join(resolvedConfig.workingDir, lockFile),
         join(outputPath, lockFile)
       );
     } catch (e) {
-      logger.debug("Failed to copy lockfile", {
+      logger.warn("Failed to copy lockfile - build may not be reproducible", {
         lockFile,
         error: e instanceof Error ? e.message : e,
       });
     }
   }
packages/cli-v3/src/deploy/buildImage.test.ts (1)

1-4: Minor: Remove leading empty line.

There's an unnecessary empty line at the start of the file.

✨ Proposed fix
-
 import { describe, it, expect } from "vitest";
 import { generateContainerfile, GenerateContainerfileOptions } from "./buildImage.js";
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ccb8c1 and 4621b9c.

📒 Files selected for processing (4)
  • .changeset/fix-cli-deploy-yarn-workspaces.md
  • packages/cli-v3/src/build/buildWorker.ts
  • packages/cli-v3/src/deploy/buildImage.test.ts
  • packages/cli-v3/src/deploy/buildImage.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/build/buildWorker.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/build/buildWorker.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use vitest for all tests in the Trigger.dev repository

Files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/build/buildWorker.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/build/buildWorker.ts
**/*.test.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.{ts,tsx,js,jsx}: Test files should live beside the files under test and use descriptive describe and it blocks
Tests should avoid mocks or stubs and use the helpers from @internal/testcontainers when Redis or Postgres are needed
Use vitest for running unit tests

**/*.test.{ts,tsx,js,jsx}: Use vitest exclusively for testing and never mock anything - use testcontainers instead
Place test files next to source files with naming pattern: source file (e.g., MyService.ts) → MyService.test.ts

Files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use testcontainers helpers (redisTest, postgresTest, containerTest) from @internal/testcontainers for Redis/PostgreSQL testing instead of mocks

Files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
{packages,integrations}/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Add a changeset when modifying any public package in packages/* or integrations/* using pnpm run changeset:add

Files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
  • packages/cli-v3/src/deploy/buildImage.ts
  • packages/cli-v3/src/build/buildWorker.ts
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Use build extensions in trigger.config.ts (additionalFiles, additionalPackages, aptGet, prismaExtension, etc.) to customize the build
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to {packages,integrations}/**/* : Add a changeset when modifying any public package in `packages/*` or `integrations/*` using `pnpm run changeset:add`
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to {packages,integrations}/**/* : Add a changeset when modifying any public package in `packages/*` or `integrations/*` using `pnpm run changeset:add`

Applied to files:

  • .changeset/fix-cli-deploy-yarn-workspaces.md
  • packages/cli-v3/src/build/buildWorker.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Use build extensions in trigger.config.ts (additionalFiles, additionalPackages, aptGet, prismaExtension, etc.) to customize the build

Applied to files:

  • .changeset/fix-cli-deploy-yarn-workspaces.md
  • packages/cli-v3/src/build/buildWorker.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks

Applied to files:

  • .changeset/fix-cli-deploy-yarn-workspaces.md
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : When importing from `trigger.dev/core` in the webapp, use subpath exports from the package.json instead of importing from the root path

Applied to files:

  • .changeset/fix-cli-deploy-yarn-workspaces.md
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.{ts,tsx} : Always import tasks from `trigger.dev/sdk`, never use `trigger.dev/sdk/v3` or deprecated `client.defineJob` pattern

Applied to files:

  • .changeset/fix-cli-deploy-yarn-workspaces.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation

Applied to files:

  • .changeset/fix-cli-deploy-yarn-workspaces.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties

Applied to files:

  • .changeset/fix-cli-deploy-yarn-workspaces.md
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure build process in trigger.config.ts using `build` object with external packages, extensions, and JSX settings

Applied to files:

  • .changeset/fix-cli-deploy-yarn-workspaces.md
  • packages/cli-v3/src/build/buildWorker.ts
📚 Learning: 2025-11-27T16:26:44.496Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/executing-commands.mdc:0-0
Timestamp: 2025-11-27T16:26:44.496Z
Learning: For running tests, navigate into the package directory and run `pnpm run test --run` to enable single-file test execution (e.g., `pnpm run test ./src/engine/tests/ttl.test.ts --run`)

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vitest exclusively for testing and never mock anything - use testcontainers instead

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
📚 Learning: 2025-11-27T16:26:37.432Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-27T16:26:37.432Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Use vitest for all tests in the Trigger.dev repository

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Use vitest for running unit tests

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Applies to **/*.test.{ts,tsx,js,jsx} : Test files should live beside the files under test and use descriptive `describe` and `it` blocks

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.test.{ts,tsx} : Use testcontainers helpers (`redisTest`, `postgresTest`, `containerTest`) from `internal/testcontainers` for Redis/PostgreSQL testing instead of mocks

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.test.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use logger methods (debug, log, info, warn, error) from `trigger.dev/sdk/v3` for structured logging in tasks

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.ts
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Run commands from root with `pnpm run` in this pnpm 10.23.0 monorepo using Turborepo

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.ts
📚 Learning: 2026-01-15T10:48:02.687Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-15T10:48:02.687Z
Learning: Use pnpm as the package manager (version 10.23.0 or later) and Node.js 20.20.0

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.ts
📚 Learning: 2025-11-27T16:26:44.496Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/executing-commands.mdc:0-0
Timestamp: 2025-11-27T16:26:44.496Z
Learning: Execute most monorepo commands using `pnpm run` from the root directory, with `--filter` flag for specific packages (e.g., `pnpm run dev --filter webapp`)

Applied to files:

  • packages/cli-v3/src/deploy/buildImage.ts
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure Trigger.dev project in `trigger.config.ts` using `defineConfig()` with project ref and task directories

Applied to files:

  • packages/cli-v3/src/build/buildWorker.ts
🧬 Code graph analysis (2)
packages/cli-v3/src/deploy/buildImage.ts (1)
packages/cli-v3/e2e/utils.ts (1)
  • PackageManager (13-13)
packages/cli-v3/src/build/buildWorker.ts (1)
packages/cli-v3/e2e/utils.ts (1)
  • PackageManager (13-13)
🔇 Additional comments (7)
.changeset/fix-cli-deploy-yarn-workspaces.md (1)

1-5: LGTM!

The changeset is correctly formatted, targets the appropriate package with a patch-level change, and provides a clear description of the fix referencing the issue.

packages/cli-v3/src/deploy/buildImage.ts (3)

2-2: LGTM!

The PackageManager type import from nypm and the new optional fields in GenerateContainerfileOptions are well-designed for the feature's needs.

Also applies to: 686-687


554-559: LGTM!

The cache options formatting is reorganized but preserves the original behavior.


874-878: LGTM!

The conditional lockfile copy logic is well-implemented with a helpful comment fallback for debugging when no lockfile is provided.

packages/cli-v3/src/build/buildWorker.ts (2)

3-3: LGTM!

The new imports for detectPackageManager, PackageManager, and copyFile are appropriate for the package manager detection and lockfile handling features.

Also applies to: 14-14


245-263: LGTM!

The updated writeContainerfile function signature correctly accepts and propagates the package manager and lockfile path to the container file generation.

packages/cli-v3/src/deploy/buildImage.test.ts (1)

5-50: Good test coverage for the new functionality.

The tests adequately cover the main scenarios: default npm behavior, yarn installation, pnpm installation with corepack, and lockfile copying. Consider adding tests for edge cases in a follow-up:

  • npm with package-lock.json lockfile
  • Verifying the comment appears when no lockfile is provided
  • Bun runtime behavior (if applicable)

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +1171 to +1187
function getInstallCommand(packageManager?: PackageManager | null) {
switch (packageManager?.name) {
case "yarn": {
return "RUN yarn install";
}
case "pnpm": {
return `
RUN corepack enable
RUN pnpm install
`;
}
case "npm":
default: {
return "RUN npm i --no-audit --no-fund --no-save --no-package-lock";
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

npm ci yarn pnpm --frozen-lockfile reproducible builds best practices

💡 Result:

Goal: “fail the build if the lockfile would change”

Use the package manager’s CI / immutable install mode so dependency resolution is taken from the lockfile and the install aborts if the lockfile and manifests are out of sync.

npm (package-lock.json / npm-shrinkwrap.json)

  • CI command: npm ci
  • Key properties: requires an existing lockfile, errors if lockfile doesn’t match package.json, removes existing node_modules, and never writes package.json / lockfiles. [1]

Yarn

Yarn 1 (Classic)

  • CI command: yarn install --frozen-lockfile (fails if yarn.lock would need changes). [2]

Yarn 2+ (Berry / modern Yarn)

  • CI command: yarn install --immutable
  • Notes: --immutable defaults to true on CI, fails if the lockfile would be modified; --frozen-lockfile exists as an alias for backward compatibility (planned removal in a later release). [3]
  • For stricter reproducibility in “Zero-Installs” setups: yarn install --immutable --immutable-cache (and optionally --check-cache). [3]

pnpm (pnpm-lock.yaml)

  • CI command: pnpm install --frozen-lockfile
  • Notes: --frozen-lockfile defaults to true on CI (when a lockfile is present) and fails if the lockfile is out of sync / would need updates. [4]

Reproducible-build best practices (works across npm/Yarn/pnpm)

  1. Commit exactly one lockfile (package-lock.json or yarn.lock or pnpm-lock.yaml) and don’t mix package managers in the same repo.
  2. Pin the package manager version (so the same lockfile semantics/resolver are used everywhere), and use the pinned version in CI.
  3. Pin Node.js (major/minor) for CI and releases; native addons and resolution edge-cases can vary by Node version.
  4. Keep install flags/config consistent between lockfile generation and CI (example: npm notes that flags like --legacy-peer-deps used during npm install should also be used for npm ci, otherwise CI may fail). [1]
  5. Treat lockfile updates as code changes: update via the package manager, review diffs, and avoid manual edits.

Quick “CI install” command cheat-sheet

# npm
npm ci

# Yarn 1
yarn install --frozen-lockfile

# Yarn 2+
yarn install --immutable

# pnpm
pnpm install --frozen-lockfile

Sources: npm ci docs [1]; Yarn classic --frozen-lockfile docs [2]; Yarn modern --immutable / CI behavior docs [3]; pnpm --frozen-lockfile / CI default docs [4].


🏁 Script executed:

# Search for issue `#2914` reference in the repo
rg "2914" --type ts --type md --type json

# Look for context in buildImage.ts around the install command generation
fd buildImage.ts -x cat -n {} | head -100

Repository: triggerdotdev/trigger.dev

Length of output: 3348


🏁 Script executed:

# Check if there are any GitHub issue links or comments in the relevant files
rg "frozen-lockfile|npm ci|reproducible.*build" packages/cli-v3/src/deploy/ -A 2 -B 2

Repository: triggerdotdev/trigger.dev

Length of output: 51


🏁 Script executed:

# Find and examine buildImage.ts more carefully
fd buildImage.ts -x wc -l {}

Repository: triggerdotdev/trigger.dev

Length of output: 116


🏁 Script executed:

# Look at lines around 1171-1187 in buildImage.ts
fd buildImage.ts -x sed -n '1150,1200p' {}

Repository: triggerdotdev/trigger.dev

Length of output: 892


🏁 Script executed:

# Search for any issue/PR references related to reproducible builds or frozen-lockfile
rg "issue|PR|frozen.*lock|reproducible" packages/cli-v3/src/deploy/buildImage.ts -B 2 -A 2

Repository: triggerdotdev/trigger.dev

Length of output: 3565


🏁 Script executed:

# Check if there's a .yarn-version or .node-version or similar to understand which Yarn version is used
fd -e "versions" -e "npmrc" -e "yarnrc" -e "pnpmfile" packages/cli-v3/

Repository: triggerdotdev/trigger.dev

Length of output: 438


🏁 Script executed:

# Check package.json for packageManager field to see which version is pinned
rg '"packageManager"' packages/cli-v3/package.json

Repository: triggerdotdev/trigger.dev

Length of output: 51


🏁 Script executed:

# Check root package.json for packageManager field
cat package.json | grep -A 2 -B 2 "packageManager"

Repository: triggerdotdev/trigger.dev

Length of output: 184


🏁 Script executed:

# Check what lockfiles exist in repo to determine package manager versions
git ls-files | rg -E "yarn\.lock|pnpm-lock\.yaml|package-lock\.json" | head -5

Repository: triggerdotdev/trigger.dev

Length of output: 465


🏁 Script executed:

# Check for lockfiles to understand which package managers are used
git ls-files | grep -E "yarn\.lock|pnpm-lock\.yaml|package-lock\.json"

Repository: triggerdotdev/trigger.dev

Length of output: 956


🏁 Script executed:

# Check if there's any yarn version specification
cat .yarnrc.yml 2>/dev/null || cat .yarnrc 2>/dev/null || echo "No yarn config found"

Repository: triggerdotdev/trigger.dev

Length of output: 89


🏁 Script executed:

# Look at the context around lockfile copying in buildImage.ts to understand the full picture
sed -n '860,900p' packages/cli-v3/src/deploy/buildImage.ts

Repository: triggerdotdev/trigger.dev

Length of output: 1012


Install commands don't ensure reproducible builds.

The implementation should use CI/immutable install modes to fail if lockfiles are out of sync: npm ci for npm, --frozen-lockfile for yarn and pnpm. The current npm i with --no-package-lock explicitly prevents reproducible builds, and the pnpm case creates multiple Docker layers unnecessarily.

🔧 Proposed fix
 function getInstallCommand(packageManager?: PackageManager | null) {
   switch (packageManager?.name) {
     case "yarn": {
-      return "RUN yarn install";
+      return "RUN yarn install --frozen-lockfile";
     }
     case "pnpm": {
-      return `
-      RUN corepack enable
-      RUN pnpm install
-      `;
+      return "RUN corepack enable && pnpm install --frozen-lockfile";
     }
     case "npm":
     default: {
-      return "RUN npm i --no-audit --no-fund --no-save --no-package-lock";
+      return "RUN npm ci";
     }
   }
 }
🤖 Prompt for AI Agents
In `@packages/cli-v3/src/deploy/buildImage.ts` around lines 1171 - 1187,
getInstallCommand currently prevents reproducible installs and creates extra
Docker layers; update it so npm uses "npm ci" (not "npm i"), yarn uses a
frozen/CI mode (e.g., "yarn install --frozen-lockfile"), and pnpm runs corepack
enable and install in a single RUN with pnpm's frozen-lockfile flag (e.g.,
"corepack enable && pnpm install --frozen-lockfile") to avoid multiple layers;
modify the switch in getInstallCommand (check packageManager?.name) to return
these CI/immutable install commands and remove the
"--no-package-lock/--no-audit" pattern that disables lockfile enforcement.

@nicktrn nicktrn closed this Feb 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: trigger deploy hardcodes npm install, breaking Yarn workspaces

2 participants